/*
 * FifteenPuzzleNodeA.h
 *
 *  Created on: 22/05/2011
 *      Author: frandres
 */

#ifndef FIFTEENPUZZLENODEA_H_
#define FIFTEENPUZZLENODEA_H_
#include <limits.h>
#include <vector>
using namespace std;

#include "../heuristics/Manhattan15Puzzle.h"
#include "../heuristics/PDBHeuristic.h"

#pragma pack(push,1)

#define MOVE_UP 0
#define MOVE_DOWN 1
#define MOVE_LEFT 2
#define MOVE_RIGHT 3

class FifteenPuzzleNodeA{
public:
	FifteenPuzzleNodeA();
	FifteenPuzzleNodeA(int board[], int movements, int h, int g);
	~FifteenPuzzleNodeA();

	/*
	 * Getboard lee el arreglo de bytes, descomprimiendo la
	 * representación en un arreglo de enteros.
	 *
	 * El arreglo devuelto especifica el tablero de un 15-puzzle.
	 * La i-esima posición del arreglo especifica que número está
	 * en la casilla i-ésima del 15 puzzle.
	 *
	 * Ejemplo:
	 *
	 *  _ _  _ _  _ _  _ _
	  |   0|   1|   2|   3|
	  |1 _ |15 _|14 _|2 _ |
	  |   4|   5|   6|   7|
	  |10 _|8 _ |11 _|3 _ |
	  |   8|   9|  10|  11|
	  |7 _ |9 _ |4 _ |12 _|
	  |  12|  13|  14|  15|
	  |13 _|5 _ |_ _ |6 _ |

	  board[0] contiene 1, board [1] contiene 15 y así...
	  */
	void getBoard(int board[]);

	void getInvBoard(int invBoard[]);

    // Devuelve un tablero con el tablero del padre.
    void getFather(int board[]);

    /* Devuelve un número que especifica el momiento necesario
     * para llegar al padre, MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT
     */
    int getFatherMovements();

    /* Setea un número que especifica el momiento necesario
     * para llegar al padre, MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT
     */
    void setFatherMovements(int movement);

    // Devuelve la posición de un número en el rango 0-15.
    int getPosicion(int numero);

    // Asigna el valor de la posición de un número en el rango 0-15.
    void setPosiciones(int newBoard[]);

    void setH(int newH);

    int getH();

    void setG(int newG);

    int getG();

    int getF();

    void setHeapIndex(unsigned int newHeapIndex);

    unsigned int getHeapIndex();

    inline unsigned char toBinary(int numero);

	vector<FifteenPuzzleNodeA *> getSuccesors(Manhattan15Puzzle *h);

	vector<FifteenPuzzleNodeA *> getSuccesors(PDBHeuristic *h1, PDBHeuristic *h2, PDBHeuristic *h3);

	vector<FifteenPuzzleNodeA> getSuccesors(int board[], int invBoard[], PDBHeuristic * h1, int dh);

    void printBoard();
    void printMov();
    static unsigned char toBinaryArray[128];

    /*
     * Para identificar la posición de los 12 primeros números (0-11), se
     * enumeran las permutaciones y se guarda dicho valor en un unsigned int.
     *
     * Las posiciones remanentes se guardan en chars en la variable board.
     * Esto permite guardar todo el tablero en examente 6 bytes, dado que por lo
     * general un int ocupa 4 bytes.
     */

    unsigned int permutationRank;
    /* Este número sirve para identificar en que posición del heap de la lista de abierto
       se encuentra el nodo.
    */


    unsigned int heapIndex;

    /*
     * board contiene la información del tablero y del estado
     * del fifteen puzzle en un arreglo de 3 bytes.
     *
     * Los primeros 16 bits contienen información para determinar donde
     * están los números 12,13,14 y 15.
     *
     * Los bits 17 y 18 especifican el momiento necesario para alcanzar el padre:
     *  * 00 indica mover la casilla blanca a la derecha.
     *  * 01 indica mover la casilla blanca a la izquierda.
     *  * 10 indica mover la casilla blanca a arriba.
     *  * 11 indicar mover la casilla blanca a abajo.
     *
     *  Los bits en el rango 19-25 (7 bits) guardan el valor de la g del estado.
     *  Los bits en el rango 26-32 (7 bits) guardan el valor de la heuristica del estado.
     *
     *  Estas dos últimas cosas son válidas dado que para el fifteen puzzle, el máximo
     *  número de momientos es 81. Con 7 bits se puede almacenar un número hasta 128.
     *  Como las heurísticas son admisibles, necesariamente h<g.
     *
     */
     unsigned char dBoard[4];


    /* Estas 4 funciones usan el algoritmo lineal de Myrvold & Ruskey para rankear
     * la permutación formada por los 12 primeros números del tablero, en orden invertido.
     * La permutación que se rankea es un arreglo cuya primera posición indica en que
     * posición está el 0, en su segunda posición indica donde esta el uno y así
     * sucesivamente, siempre con valores del 0 al 12, ya que no se cuentan las posiciones
     * en las que están el 12,13,14 y 15.
     */
	unsigned int rrankPerm(int n, int perm [] , int invPerm []);
	void unrankPerm(int n, int r, int * perm);
	void calculatePermInverse( int n,int perm [],int * invPerm);
	inline void swapPermutation (int perm [], int pos1, int pos2);

};

#endif /* FIFTEENPUZZLENODEA_H_ */
